package com.pfe.myrobot;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.IntentFilter;
import android.graphics.Typeface;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.pfe.myrobot.RobotReceiver.OnHitReceiverListener;
import com.pfe.myrobot.WifiStateReceiver.OnWifiPowerListener;
import com.pfe.myrobot.WifiStateReceiver.OnWifiStateListener;
import com.pfe.myrobot.controllers.JoystickView;
import com.pfe.myrobot.controllers.JoystickView.OnJoystickMoveListener;
import com.pfe.myrobot.controllers.ProgressButton;

public class GameActivity extends Activity implements SurfaceHolder.Callback, OnPreparedListener, OnWifiStateListener, OnWifiPowerListener {
	
	//Network macro
	//public static final String SERVER_IP = "192.168.137.1";
	public static final String SERVER_IP = "10.0.0.1";
	public static final int SERVER_PORT = 9999;
	public static final String videoSrc = "http://10.0.0.1:8090";
	//public static final String videoSrc = "rtsp://192.168.137.1:8554/video";
	//public static final String videoSrc = "http://192.168.137.1:8080/video";
	//public static final String videoSrc = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8";
	
	//Game macro
	public static final String GAME_MODE = "gamemode";
	public static final String GAME_PARAM = "gameparam";
	public static final int END_GAME = 0;
	public static final int FREE_MODE = 1;
	public static final int VS_MODE = 2;
	
	//Time macro
	public static final long TIMER_30_MIN = 1800000; //30min
	public static final long TIMER_25_MIN = 1500000; //25min
	public static final long TIMER_20_MIN = 1200000; //20min
	public static final long TIMER_15_MIN = 900000; //15min
	public static final long TIMER_10_MIN = 600000; //10min
	public static final long TIMER_5_MIN = 300000; //5min
	public static final int RELOAD_TIME = 2000; //2sec; must be at least 500ms
	public static final int COUNT_STEP = 1000; //1sec
	
	//Parameters
	private RobotReceiver robotReceiver;
	private NewGameParameters newParams;
	
	// WiFi Management
	private WifiManager wifiManager;
	private WifiStateReceiver wifiReceiver;
	private IntentFilter actionFilter;
	
	//General surface
	private MediaPlayer mediaPlayer = null;
	private SurfaceHolder surfaceHolder;
	private SurfaceView playerSurfaceView;
	
	//Header game info
	private ProgressBar myLifeBar,yourLifeBar;
	private ImageView wifiLevel;
	
	// Dialog Interface
	private AlertDialog endAlert, lostAlert;
	private AlertDialog.Builder endBuilder, lostBuilder;
	
	//Game controllers
	private JoystickView joystick;
	private ProgressButton fireButton;
	private MyCount countDown;
	private TextView timer;
	
	//Reload Thread
	private Thread thrReload, thrJoystick;
	private FireReload fireReload;
	private JoystickSend joystickSend;
	
	//Joystick Information
	private String motD="00", motG="00";
	private int pwD=0, pwG=0;
	
	//Other variables
	private int recharge = 2000;
	int myCurrentLife, yourCurrentLife;
	private String joystickData = "";
	private int gameMode = VS_MODE;
	private long milli;
	private long sec;
	private long min;
	private int pioupiou = 0;	

	//UI
	Typeface custom_font;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);				
		setContentView(R.layout.activity_freemode);
		
		 custom_font = Typeface.createFromAsset(getAssets(), "fonts/batmfa.ttf");
		
		//Get XML views
		playerSurfaceView = (SurfaceView)findViewById(R.id.playersurface);
		timer = (TextView) findViewById(R.id.time_countdown);
		timer.setTypeface(custom_font);
		myLifeBar = (ProgressBar) findViewById(R.id.life_me);
		yourLifeBar = (ProgressBar) findViewById(R.id.life_you);
		joystick = (JoystickView) findViewById(R.id.fullscreen_content);
		fireButton = (ProgressButton) findViewById(R.id.fire_button);
		wifiLevel = (ImageView) findViewById(R.id.wifi_level_game);
        
        //Joystick Thread
      	joystickSend = new JoystickSend();
      	thrJoystick = new Thread(joystickSend);
      	thrJoystick.start();
      	
        //Initialize WiFi Service
      	wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
      	robotReceiver = new RobotReceiver();
      	
        //Initialize Intent Filters for BroadcastReceiver
      	wifiReceiver = new WifiStateReceiver(this, wifiManager);
      	actionFilter = new IntentFilter();
      	actionFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
      	actionFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
      	actionFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
      	actionFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
      	onWifiPowerChange(wifiManager.getConnectionInfo().getRssi());
        
        gameMode = getIntent().getIntExtra(GAME_MODE, FREE_MODE);        
       
        joystick.setOnJoystickMoveListener(new OnJoystickMoveListener() {        	
			@Override
			public void onValueChanged(int angle, int power, int direction) {
				joystickData = convertToSingleString(angle, power, direction);
				synchronized(joystickSend) {
					joystickSend.notify();
				}
			}
		}, JoystickView.DEFAULT_LOOP_INTERVAL);	
        
        if(gameMode == FREE_MODE) {
        	freeMode();
        }
        else if(gameMode == VS_MODE) {
        	newParams = (NewGameParameters) getIntent().getSerializableExtra(GAME_PARAM);
        	vsMode(newParams);
        }
        
        //General surface		
        surfaceHolder = playerSurfaceView.getHolder();
        surfaceHolder.addCallback(this);
	}
	
	@Override
	public void onResume() {
		super.onResume();
		registerReceiver(wifiReceiver, actionFilter);
	}

	@Override
	public void onPause() {
		super.onPause();
		unregisterReceiver(wifiReceiver);
	}

	
	private void freeMode() {
		timer.setVisibility(View.INVISIBLE);
		myLifeBar.setVisibility(View.INVISIBLE);
		yourLifeBar.setVisibility(View.INVISIBLE);
		fireButton.setVisibility(View.INVISIBLE);
	}
	
	private void vsMode(NewGameParameters newParams) {
		
		timer.setVisibility(View.VISIBLE);
		myLifeBar.setVisibility(View.VISIBLE);
		yourLifeBar.setVisibility(View.VISIBLE);
		fireButton.setVisibility(View.VISIBLE);
		
		//Header game info
		switch(newParams.getTimeLimit()) {
			case 0:
				break;
			case 5:
				countDown = new MyCount(TIMER_5_MIN, COUNT_STEP);
				countDown.start();
				break;
			case 10:
				countDown = new MyCount(TIMER_10_MIN, COUNT_STEP);
				countDown.start();
				break;
			case 15:
				countDown = new MyCount(TIMER_15_MIN, COUNT_STEP);
				countDown.start();
				break;
			case 20:
				countDown = new MyCount(TIMER_20_MIN, COUNT_STEP);
				countDown.start();
				break;
			case 25:
				countDown = new MyCount(TIMER_25_MIN, COUNT_STEP);
				countDown.start();
				break;
			case 30:
				countDown = new MyCount(TIMER_30_MIN, COUNT_STEP);
				countDown.start();
				break;
		}                
        
        myLifeBar.setRotation(180);		 
		myLifeBar.setMax(newParams.getLifeMax());
		myLifeBar.setProgress(newParams.getLifeMax());
		myCurrentLife = newParams.getLifeMax();
			
		yourLifeBar.setMax(newParams.getLifeMax());
		yourLifeBar.setProgress(newParams.getLifeMax());
		yourCurrentLife = newParams.getLifeMax();
        
        //Game controllers        
        fireButton.setMax(RELOAD_TIME);
		fireButton.setProgress(recharge);
		
		//Reload Thread
		fireReload = new FireReload();
		thrReload = new Thread(fireReload);
		thrReload.start();	
		
		fireButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				if(pioupiou == 0) {
					pioupiou = 1;
					joystickData = motG + "-" + pwG + "-" + motD + "-" + pwD + "-" + pioupiou + "-0";
					synchronized(joystickSend) {
						joystickSend.notify();
					}
					
					synchronized(fireReload) {
						fireReload.notify();
					}
				}
			}			
		});
	}	
	
	@Override
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {}

	@Override
	public void surfaceCreated(SurfaceHolder arg0) {

        try {
        	mediaPlayer = new MediaPlayer();          
        	mediaPlayer.setDisplay(surfaceHolder);
			mediaPlayer.setDataSource(videoSrc);
			mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);				
			mediaPlayer.setOnPreparedListener(this);
			mediaPlayer.prepareAsync();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	

	@Override
	public void onPrepared(MediaPlayer mp) {
		mp.start();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder arg0) {
		if (mediaPlayer != null) {
	        if(mediaPlayer.isPlaying()) {
	            mediaPlayer.stop();
	        }
	        mediaPlayer.release();
	        mediaPlayer = null;
	    }
	}
	
	private String convertToSingleString(int angle, int power, int direction) {
		
		if(angle > -180 && angle < -90){
			pwG = power;
			pwD = (int) ((((-angle)-90)* 1.11 )* ((float)power/100));
			motG = "01";
			motD = "01";	
		}else if(angle > -90 && angle < 0){
			pwG = (int) ((100 - ( -angle * 1.11 ))* ((float)power/100));
			pwD = power;
			motG = "10";
			motD = "10";
		}else if(angle > 0 && angle < 90){
			pwG = power;
			pwD = (int) ((100 - ( angle * 1.11 ))* ((float)power/100));
			motG = "10";
			motD = "10";
		}else if(angle > 90 && angle < 180){
			pwG = (int) (((angle-90)* 1.11 )* ((float)power/100));
			pwD = power;
			motG = "01";
			motD = "01";
		}else if(angle == 0){
			pwG = power;
			pwD = power;
			motG = "10";
			motD = "10";
		}else if(angle == 90){
			pwG = power;
			pwD = 0;
			motG = "10";
			motD = "00";
		}else if(angle == -90){
			pwG = 0;
			pwD = power;
			motG = "00";
			motD = "10";
		}else if(angle == -180 || angle == 180){
			pwG = power;
			pwD = power;
			motG = "01";
			motD = "01";
		}
		return motG + "-" + pwG + "-" + motD + "-" + pwD + "-" + pioupiou + "-0";
	}
	
	public void endGame(boolean winner) {
		endBuilder = new AlertDialog.Builder(this);
		if(winner) endBuilder.setTitle(R.string.dia_title_youwin);
		else endBuilder.setTitle(R.string.dia_title_youlose);
		endBuilder.setMessage(getResources().getString(R.string.dia_mes_shoot) + " " + "\n" +
				getResources().getString(R.string.dia_mes_accuracy) + " " + "\n" +
				getResources().getString(R.string.dia_mes_time) + " ");
		endBuilder.setPositiveButton(R.string.replay, new DialogInterface.OnClickListener() {			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				vsMode(newParams);
				dialog.dismiss();
			}
		});
		endBuilder.setNegativeButton(R.string.menu, new DialogInterface.OnClickListener() {			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();
				(GameActivity.this).onBackPressed();
			}
		});
		endAlert = endBuilder.create();
		endAlert.show();
	}

	class FireReload implements Runnable {
		@Override
		public void run() {
			try {
				while(gameMode == VS_MODE) {
					synchronized(this) {
						wait();
					}
					if(gameMode == VS_MODE) {
						recharge = 0;						
						while(recharge < RELOAD_TIME ) {
							synchronized(this) {
								wait(20);
							}
							recharge += 20;
							if(recharge >= 500) {
								pioupiou = 0;
								joystickData = motG + "-" + pwG + "-" + motD + "-" + pwD + "-" + pioupiou + "-0";
								synchronized(joystickSend) {
									joystickSend.notify();
								}
							}
							runOnUiThread(new Runnable() {							
								@Override
								public void run() {
									fireButton.setProgress(recharge);								
								}
							});		                
						}
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}			
	}
	
	class JoystickSend implements Runnable {
		
		DatagramSocket serverSocket;
		DatagramPacket sendPacket;
		InetAddress host;
		
		public JoystickSend() {
			try {
				serverSocket = new DatagramSocket();
				host = InetAddress.getByName(SERVER_IP);
			} catch (SocketException e) {
				e.printStackTrace();
			} catch (UnknownHostException e) {
				e.printStackTrace();
			}
		}
		
		@Override
		public void run() {
			try {
				while(gameMode != END_GAME) {
					synchronized(this) {
						wait();
					}
					if(gameMode != END_GAME) {
						byte[] sendData = joystickData.getBytes();
						sendPacket = new DatagramPacket(
								sendData, sendData.length, host, SERVER_PORT);
						serverSocket.send(sendPacket);
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	class MyCount extends CountDownTimer {

		public MyCount(long millisInFuture, long countDownInterval) {
			super(millisInFuture, countDownInterval);
		}

		@Override
		public void onFinish() {
			endGame(true);			
		}

		@Override
		public void onTick(long millisUntilFinished) {
			milli = millisUntilFinished % 1000;
			sec = ((millisUntilFinished - milli)/ 1000) % 60;
			min = ((millisUntilFinished - milli - sec)/ (1000 * 60) % 60);
			if(sec >= 10)
				timer.setText(min + ":" + sec);
			else
				timer.setText(min + ":0" + sec);
		}	
	}
	

	@Override
	public void onWifiPowerChange(int power) {
		if (power >= WifiStateReceiver.RSSI_MAX) {
			wifiLevel.setImageDrawable(getResources().getDrawable(R.drawable.wifi_level_4_50));
		} else if (power < WifiStateReceiver.RSSI_MAX
				&& power >= (WifiStateReceiver.RSSI_MAX - WifiStateReceiver.RSSI_STEP_4)) {
			wifiLevel.setImageDrawable(getResources().getDrawable(R.drawable.wifi_level_3_50));
		} else if (power < (WifiStateReceiver.RSSI_MAX - WifiStateReceiver.RSSI_STEP_4)
				&& power >= (WifiStateReceiver.RSSI_MAX - 2 * WifiStateReceiver.RSSI_STEP_4)) {
			wifiLevel.setImageDrawable(getResources().getDrawable(R.drawable.wifi_level_2_50));
		} else if (power < (WifiStateReceiver.RSSI_MAX - WifiStateReceiver.RSSI_STEP_4)
				&& power >= WifiStateReceiver.RSSI_MIN) {
			wifiLevel.setImageDrawable(getResources().getDrawable(R.drawable.wifi_level_1_50));
		} else if (power < WifiStateReceiver.RSSI_MIN) {
			wifiLevel.setImageDrawable(getResources().getDrawable(R.drawable.wifi_level_0_50));
		} else {
			wifiLevel.setImageDrawable(getResources().getDrawable(R.drawable.wifi_level_0_50));
		}
	}

	@Override
	public void onWifiStateChange(int state, String name) {
		if (state == WifiStateReceiver.WIFI_CONNECTED) {
			if(lostAlert != null && lostAlert.isShowing()) lostAlert.dismiss();
			robotReceiver.setOnHitReceiver(new OnHitReceiverListener() {			
				@Override
				public void onHitReceiverListener(int player) {
					if(player == RobotReceiver.ME) {
						myCurrentLife -= 10;
						myLifeBar.setProgress(myCurrentLife);
						if(myCurrentLife == 0) endGame(false);
					}
					else if(player == RobotReceiver.YOU) {
						yourCurrentLife -= 10;
						yourLifeBar.setProgress(yourCurrentLife);
						if(yourCurrentLife == 0) endGame(true);
					}
				}
			});
		}
		if (state == WifiStateReceiver.WIFI_DISCONNECTED) {
			robotReceiver.removeOnHitReceiver();
			lostBuilder = new AlertDialog.Builder(this);
			lostBuilder.setTitle(R.string.dia_title_lostconnect);
			lostBuilder.setNegativeButton(R.string.quit, new DialogInterface.OnClickListener() {					
				@Override
				public void onClick(DialogInterface dialog, int which) {
					(GameActivity.this).onBackPressed();
					dialog.dismiss();
				}
			});
			lostBuilder.setPositiveButton(R.string.reconnect, new DialogInterface.OnClickListener() {					
				@Override
				public void onClick(DialogInterface dialog, int which) {
					wifiManager.reconnect();
					dialog.dismiss();
				}
			});
			lostAlert = lostBuilder.create();
			if(!lostAlert.isShowing()) lostAlert.show();
		}		
	}
}
